5 1* {A Järjestelmäohjelmoinnin alkeiskurssi - Osa 4: GUI {A ------------------------------------------------- {7 Sami Klemola Alun perin tässä osassa, jonka olisi pitänyt tulla julkaistuksi jo hyvän aikaa sitten, oli tarkoituksena käsitellä Intuitionia edelleen, mutta teemme nyt hieman yllättävän käännöksen matkallamme kohti Amigan käyttöjärjestelmän hallintaa. Käsittelemme kyllä edelliseen osaan jatkona menut ja gadgetit eli valikot ja nappulat. Emme kuitenkaan tee niitä suoraan Intuitionin kanssa kommunikoiden, vaan tutustumme GadToolsin päälle asettuvaan GUI-kirjastoon nimeltä Triton. GUI:n eli graafisen käyttöliittymän tekeminen helpottui sanottavasti Release 2:n myötä sen esiteltyä uuden gadtools.libraryn. Asiat ovat kuitenkin edenneet vielä siitä, ja nyt uusinta uutta ovat kolmansien osapuolien tuottamat oliopohjaiset kirjastot. Niistä ehkäpä tunnetuin on MUI, mutta se on käyttökelvoton suunnattoman muistinkulutuksensa ja järjettömän hitautensa takia. Omaan käyttööni valitsin Tritonin, koska se on nopea ja pienikokoinen. Lisäksi sitä on helppo ohjelmoida, ja sen kanssa graafisen käyttöliittymän tekeminen on todella helppoa. Triton hoitaa kaikki yhteydet Intuitioniin ja GadToolsiin sekä tarjoaa Intuitionin peruspalveluiden ja vielä GadToolsin toimintojen lisäksi joukon omiaan. Kaikki nämä ovat Tritonin kanssa olioita, joiden käsittely on erittäin yksinkertaista. Oliot toimivat itsenäisesti Tritonin alaisuudessa, ja niiden kanssa voidaan olla tekemisissä sen kautta. Niiden tilasta saadaan tietoja ja niiden tilaa voi muuttaa. Kun käyttäjä aktivoi olion, Triton kertoo siitä ohjelmalle lähettämällä viestin. Triton-ohjelman toiminta on viestien vastaanottamista ja niiden pohjalta toimimista. Tritonin kanssa ohjelma voi keskittyä olennaiseen, ja ohjelmoija voi tyystin unohtaa ongelmat erikokoisten kirjasinten ja ikkunan koon muuttumisen kanssa. Triton on osittain sharewarea. Itse kirjaston käyttämisestä ohjelmien ajamiseen ja omien ohjelmien tekemiseen ei tarvitse maksaa mitään, mutta Tritoniin kuuluu Prefs-editori, jolla voidaan asetella kunkin Triton-ohjelman ikkunat sopiviksi, ja sen käytöstä pitää maksaa 15 dollarin tai 20 Saksan markan suuruinen hinta. Rekisteröity versio pitää siis muistissa ikkunoiden paikat, ja ohjelmien ikkunat aukeavat aina niin kuin olet ne viimeksi asettanut! Tämä artikkeli ei ole kattava opastus graafisen käyttöliittymän tekemiseen Tritonilla. Itse asiassa tässä on vain pieniä tiedonpalasia sieltä täältä, mutta kunnollista kokonaisuutta ei saa muodostettua ennen kuin tutustuu lähemmin Tritonin omaan dokumentaatioon. Jossakin tulevassa osassa voimme vielä palata Tritoniin esimerkiksi olioiden läpikäymisen merkeissä, mutta toistaiseksi tietoa niistä on aika vähän. Käydään kuitenkin asiaan ja tutustumaan Tritoniin. {3Triton Triton on kirjoitettu kirjastoksi, jota käytetään samalla tavalla kuin käyttöjärjestelmän omiakin kirjastoja. Kirjasto avataan normaalisti, ja sen jälkeen avataan Triton-projekti. Projekti käsittää ikkunan, jossa voi olla valikoita ja sisältönä kaikenlaisia olioita. Ne kuvataan makrojen avulla tavalla, joka tuo mieleen jonkinlaisen ohjelmoinnin opetuksessa käytetyn pseudokielen. Tritonille kerrotaan, mitä halutaan mihinkin kohtaan, ja se tekee oliot, laskee niille koon ja paikan jne. Tritonissa on "layout engine", joka toimii kaikenkokoisilla kirjasimilla ja osaa laskea olioille uuden koon ikkunan koon muuttuessa. Kirjaston avaamiseen voit tutustua kurssin aiemmissa osissa. Tritonin avaamisen jälkeen luodaan sovellus, mikä kuuluu alkutoimenpiteisiin. Tässä on lyhyt koodi, joka tekee sen: struct TR_App *App; if(App=TR_CreateAppTags( TRCA_Name, "MyApp", TRCA_Release, "1.0", TRCA_Version, "42.113", TRCA_Date, "3.11.94", TAG_END)) { /* Avattu */ TR_DeleteApp(App); } else { /* Virhe */ } Helpompi tapa kuitenkin on käyttää triton.lib-apukirjastossa olevia TR_OpenTriton()- ja TR_CloseTriton()-funktioita, jotka tekevät molemmat, eli TR_OpenTriton() avaa ensin kirjaston ja luo sitten sovelluksen. Sovellus on struct Application, jossa Triton pitää kaikki ohjelmaasi koskevat tiedot. Sovellukseen voidaan myöhemmin avata yksi tai useampia projekteja. Projekti on nykyään sama kuin yksi Triton-ikkuna. Projektin määrittelyssä kuvataan ensin ikkunan ominaisuudet, sitten valikot ja lopuksi ikkunan sisältö. Esimerkki projektin avaamisesta: struct TagItem dummyTags = { TRWI_Title, (ULONG) "A dummy window", TRWI_ID, 42, TAG_END }; void dummyFunction(void) { struct TR_Project *dummyProject; if(dummyProject=TR_OpenProject(Application,dummyTags)) { /* Onnistui */ TR_CloseProject(dummyProject); } else { /* Virhe */ } } Projektilla tulee olla yksilöllinen tunniste (TRWI_ID). Sen pitää olla muu kuin nolla, ja sen pitää pysyä samana. Triton tallentaa ikkunan koon ja muut parametrit, joten ne hukkuvat, jos ID muuttuu joskus. Yllä olevassa koodissa on staattinen taglista projektin kuvaamiseen. Triton ei tue TAG_MORE-toimintoa, joten listoja ei voi yhdistellä. Joskus voi olla tarpeen käyttää TR_OpenProjectTags()-kutsua sen sijaan, jolloin taglista rakennetaan dynaamisesti ja ajoaikaisesti pinoon. Tämä tietysti kuluttaa paljon pinomuistia sekä pidentää ja hidastaa ohjelmaa, joten kovin pitkiä taglistoja ei kannata näin rakennella. Yllä olevissa koodeissa käytetään tagien nimiä, mutta paljon selkeämpi tapakin taglistojen tekemiseen on olemassa: makrot. Niillä voidaan kuvata melkein kaikki tarpeellinen. Esimerkiksi ikkuna kuvataan näin: WindowTitle("A dummy window"), WindowID(42), EndProject Myös olioille ja valikkovalinnoille on olemassa makrot. Tarkemmin määrittelyjen tekeminen ja makrojen käyttäminen siinä selviää artikkelin lopussa olevasta ohjelmaesimerkistä. {2Oliot Tritonin toiminta perustuu olioihin ja ohjelman käyttäjän kanssa käymä kommunikaation niiltä saataviin viesteihin. Tässä on aluksi luettelo kaikista Triton-olioista: Button BOOPSI button gadget CheckBox GadTools CheckBox Cycle GadTools Cycle and MX gadget DropBox AppIcon dropping box FrameBox Framing or grouping box Group Triton's layout engine Image Image Line 3D line Listview GadTools Listview Palette GadTools Palette gadget Progress Progress indicator Scroller GadTools Scroller Slider GadTools Slider Space Empty space String GadTools String gadget Text Text Taulukko 1. Triton-oliot. Näistä muutamat ovat yksinkertaisia: Text näyttää tekstiä, Line tekee viivan ja niin edelleen. Sitten on todella monimutkaisia ja kehittyneitä olioita kuten palettigadget, Listview-gadget ja Progress indicator eli valmiiksi rakennettu edistysosoitin, jossa on tiettyyn suuntaan työn etenemisen mukaan virtaava palkki, joten käyttäjä näkee, missä vaiheessa työ on. Group-olio liittyy Tritonin layout engineen. Sen avulla voidaan ohjata olioiden sijoittelua ikkunaan. Niitä voidaan ryhmitellä pysty- ja vaakasuunnassa, keskittää ja jaotella eri tavoin. Tässä jutussa en käy olioita läpi yksityiskohtaisesti, mutta lopun lähdekoodissa on hieman asiaa niistä. Asiaan voidaan palata jatkossa. Olioilla on attribuutteja, joiden arvo voidaan lukea funktiolla TR_GetAttribute(). Niitä voidaan myös asettaa funktiolla TR_SetAttribute(). Joidenkin olioiden kaikkia attribuutteja ei voida muuttaa jälkikäteen, vaan arvot ovat pysyviä, kun ne luomishetkellä on määritelty. Tällaisia muuttamattomia attribuutteja on esimerkiksi Listview-gadgetin entrylista. {2Viestit Tritonilta saadaan monenlaisia viestejä. Se voi kertoa ikkunan sulkunappulan painamisesta tai sisäisestä virheestä. Tärkeimmät viestit ovat NEWVALUE ja ACTION. Ne ovat olioiden lähettämiä viestejä ja kertovat, että käyttäjä on tehnyt niille jotakin. Nappulaa voi olla painettu tai vieritintä vieritetty. Viestiin sisältyy tarkka tieto siitä, mitä on tapahtunut. Triton-ohjelman toiminta perustuu viestien vastaanottamiseen ja niiden tulkintaan. Yksi lähdekoodi kertoo enemmän kuin kaksituhatta tavua, joten tämäkin selviää parhaiten esimerkkikoodista. Myös oliot keskustelevat Tritonin kanssa viesteillä. Näiden viestien kanssa sovellus ei kuitenkaan ole yleensä tekemisissä. Sen sijaan esimerkiksi TR_SetAttribute()-funktion kutsuminen saa Tritonin lähettämään kohdeoliolle asianmukaisen viestin. Olioille voi kyllä lähettää suoraankin viestejä, mutta se ei ole yleensä tarpeen. Kaikki kanssakäyminen niiden kanssa voidaan toteuttaa helposti Tritonin kautta. {2Help Tritonissa on kaksi apua-toimintoa. QuickHelp-toiminto ollessaan päällä näyttää ruudulla pieniä aputekstejä, kun hiiren osoitin on sellaisen olion päällä, jolle on sellainen määritelty. Monet oliot eivät kuitenkaan tue tätä toimintoa vielä. Ohjelmaesimerkissä QuickHelp on päällä oletuksena ja sen tilaa voi muuttaa valikosta. Ylemmässä nappulassa on määriteltynä pieni aputeksti. Alempaan cycle-gadgetiin ei sellaista saa, koska kyseinen olio kuuluu niihin, jotka eivät peri attribuutteja yläluokilta. QuickHelp kun on abstraktin DisplayObject-luokan attribuutti eikä GUI-olioiden itsensä. Toinen tapa on manuaalinen helppi. Jos projektimäärittelyssä on TWRF_HELP päällä, Triton lähettää TRMS_HELP-viestin joka kerta, kun käyttäjä painaa Help-näppäintä. Sen jälkeen on sinun vastuullasi näyttää käyttäjälle hänen haluamaansa apua. Tavallisinta on avata ohjelman AmigaGuide-dokumentti siitä kohtaa, jossa käsitellään sitä asiaa. Viestin ID-kentässä on sen olion tunniste, josta käyttäjä haluaa tietoa. {2Loppusanat Tarkempaa tietoa Triton-ohjelmoinnista saat Developer/TritonDev.guide-dokumentista ja Tritonin includetiedostosta sekä autodoceista. Niissä on selitetty kaikki kirjastoon liittyvät asiat. Tämän artikkelin ei missään nimessä ollutkaan tarkoitus olla tyhjentävä selvitys Triton-ohjelmoinnista. Siihen ei millään olisi aikaa eikä tilaa. Monia kysymyksiä jää auki ja monet asiat ehkäpä sekaviksi, mutta lukemalla Tritonin ohjeita ne selviävät. Tarkoitukseni olikin lähinnä tarjota helppo johdanto tähän kiehtovaan GUI-maailmaan, jonka tarjoaa Triton! {3Ohjelmakoodia Tässä on kätevä ohjelmarunko, josta voi todella nopeasti tehdä pienen ohjelman. Siinä on kaikki tarvittava AmigaDOS-standardisen ohjelman tekemiseksi. Se käsittelee argumentit, sisältää cleanup-koodin sekä tarvittavan koodin virheilmoituksen näyttämiseen. Korvaa alussa kommentissa ja versiomerkkijonossa oleva "`"-merkki ohjelman nimellä (kätevästi esim. Edissä "2e/`/Ohjelma"), laita ohjelman argumenttikuvaus template-merkkijonoon ja ala kirjoittaa koodia! Puitteet ovat valmiit. Koodi käyttää _main()-entrypointtia, kuten yleensäkin, koska sillä päästään eroon monesta kilosta turhaa koodia, esimerkiksi C-kääntäjän argumenttien parseamisesta, joka on AmigaDOS-ympäristössä tarpeetonta. Koodi käyttää sen tekemiseen DOS-funktiota ReadArgs(), johon tutustumme lähemmin kurssin tulevissa osissa. ReadArgs() käsittelee argumentit standardilla tavalla, ja se myös varmistaa, että saat tarvitsemasi argumentit. Jos niitä ei ole annettu, koodi tulostaa virheilmoituksen ja palauttaa sinut shelliin. Käytettävissäsi on myös ohjelman nimi cmd-puskurissa. Sitä käytetään virheilmoitusten näyttämiseen, ja koodi kysyy sen ensi töikseen DOSilta. Argumentit ovat args-taulukossa, ensimmäisessä alkiossa ensimmäinen jne. Mikäli argumentti on merkkijono, alkiossa on osoitin siihen. Jos se on numeraalinen, alkio on nolla, jos sitä ei ole annettu (mikäli sen voi jättää antamatta), tai OSOITIN longwordiin, jossa on argumentin arvo. Argumentit kuvataan nk. templatella, jonka AmigaDOS-ohjelmat kertovat antamalla ainoaksi argumentiksi kysymysmerkin. Template voi olla esimerkiksi "FILE/A,LENGTH/N". Tällöin FILE on ensimmäinen argumentti ja merkkijono. LENGTH on toinen ja numeraalinen. Argumentin nimen perässä tulevat kirjaimet kertovat sen tyypin. A tarkoittaa pakollista argumenttia. Jos se puuttuu, ohjelma ei lähde käyntiin. N tarkoittaa numeraalista argumenttia. LENGTH-argumentissa ei ole A-määrittelyä, joten se ei ole pakollinen. Jos sitä ei anneta, args[1] on nolla. Määrittelyjä voi yhdistää, ja esimerkiksi pakollinen numeraaliargumentti olisi "/N/A". Kaikki määrittelyt on selitetty Using The System Software -kirjassa sivulla 8-5 (sekä enemmän ohjelmoijan näkökulmasta dos.libraryn autodoceissa ReadArgs()-funktion yhteydessä). Kerron niistä vielä lisää kurssin DOSia käsittelevässä osassa. /* `.c */ #include "exec/io.h" #include "exec/memory.h" #include "exec/libraries.h" #include "exec/execbase.h" #include "dos/dos.h" #include "proto/exec_protos.h" #include "proto/dos_protos.h" #define TRUE 1 #define FALSE 0 typedef unsigned char u_char int _main(void); void error(u_char *),cleanup(void); struct RDArds *ra; ULONG args[2]; u_char template[]="",ver[]="$VER: ` 1.00",cmd[32]; int _main(void) { LONG i; GetProgramName(cmd,32); if(!(ra=ReadArgs((STRPTR)template,args,NULL))) { PrintFault(i=IoErr(),cmd); exit(i); } /* Tähän koodi. */ cleanup(); return(RETURN_OK); }; void error(u_char *str) { printf("%s: %s\n",cmd,str); cleanup(); exit(RETURN_FAIL); }; void cleanup(void) { if(ra) FreeArgs(ra); }; {2Toimiva GUI-ohjelma Nyt tulee kurssin ensimmäinen täydellinen lähdekoodi, joka kääntyy täydeksi ohjelmaksi. Mitään se ei kyllä tee, mutta se rakentaa yksinkertaisen graafisen käyttöliittymän, ja koodista voi kommentoinnin myötävaikutuksella oppia paljon Tritonin käyttämisestä. Lähdekoodin osia tai koko koodiakin saa käyttää omissa ohjelmissaan. Maininta sen alkuperästä on kyllä suotavaa. Voit joutua muuttamaan koodista pieniä osia kuten prototyyppimäärittelytiedostojen nimiä tai muiden include-tiedostojen hakemistoja tai muuta sellaista saadaksesi sen kääntymään. Koodi kuitenkin kääntynee sellaisenaan. Itse käänsin sen DICE:llä ja GCC:llä. Koodi on alun perin kirjoitettu edellä nähdyn yleispohjan päälle. Nyt tästä koodista saa rungon GUI-ohjelmalle. Projektimäärittelyjä ja pääsilmukan toimintoja muuttamalla voi helposti tehdä ohjelman, jossa on hieno graafinen käyttöliittymä. Jos haluat koodista dokumentoimattoman version, jota ei ole myöskään pilkottu useammille riveille, saat sen minulta pyytämällä. Avustan myös boksissani henkilökohtaisesti ohjelmointiteknisissä ongelmatilanteissa. /* TritonCode.c */ /* Tämä lähdekoodi on pohja mille tahansa ohjelmalle, jossa on graafinen käyttöliittymä. Koodista voi helposti rakennella valmiin ohjelman. */ #include "exec/io.h" #include "exec/memory.h" #include "exec/libraries.h" #include "exec/execbase.h" #include "dos/dos.h" #include "libraries/triton.h" #include "proto/exec_protos.h" #include "proto/dos_protos.h" #include "proto/triton_protos.h" #define TRUE 1 #define FALSE 0 typedef unsigned char u_char /* Tämä on oma Triton-oliomäärittelymakroni. Se on CenteredButton, johon on ujutettu mukaan help-stringi. Alun perin se on ollut yhdellä rivillä, ja se kannattaa siihen muotoon palauttaa. Silloin voi ottaa pois rivien lopuissa olevat kenoviivat, jotka saavat kääntäjän jättämään seuraavan rivinvaihdon huomiotta, mikä on tarpeen, koska makromäärittelyn pitää olla samalla rivillä. Näinkin se toimii, mutta hyvältä se ei näytä. */ #define CenteredButtonHelp(t,i,str) HorizGroupSC,Space,TROB_Button,0L,\ TRAT_Text,(ULONG)(t),TRAT_ID,(i),TRDO_QuickHelpString,((ULONG)(str)),\ Space,EndGroup int _main(void); void DoStuff(void),error(u_char *),cleanup(void); struct RDArds *ra; struct TR_Project *project; /* Osoitin Triton-projektiin */ struct TR_Message *trmsg; /* Vastaanotettu viesti */ ULONG args[2]; /* Yleisiä merkkijonoja, versio, virheilmoitukset jne. Ohjelman nimi on s_prg:ssä, jota käytetään ohjelmassa aina, kun sitä tarvitaan. */ u_char template[]="",ver[]="$VER: TritonCode 1.00",cmd[32], err_gui[]="unable to create GUI",s_prg[]="TritonCode"; /* Kiertonappulan vaihtoehdot. Nämä merkkijonot kiertävät nappulassa aina kun sitä painetaan. */ u_char *CycleEntries[] = { "Poutaa","Pilvistä","Sadetta","Myrskyä",0 }; /* Nämä ovat ohjelmassa käytettävien Triton-olioiden tunnistenumerot. Ensimmäiset kolme ovat valikkovalintoja ja loput ikkunassa olevia nappuloita. Pidän ne eri kymmenluvuilla selvyyden vuoksi. */ #define ID_About 1 #define ID_Help 2 #define ID_Quit 3 #define ID_Ask 10 #define ID_Cycle 11 /* Tämä on Triton-projektin määrittely. Se kuvaa projektin käyttämän ikkunan, valikot ja ikkunan sisällön eli nappulat ja muut jutut. */ ProjectDefinition(prod) { WindowID(1), WindowPosition(TRWP_CENTERSCREEN), WindowTitle("TritonCode 1.00"), BeginMenu("Project"), /* Valikko */ MenuItem("A_About",ID_About), /* Ensimmäinen valinta */ MenuItemCC("H_Autohelp",ID_Help), /* CheckMark-valinta */ ItemBarlabel, /* Välirivi */ MenuItem("Q_Quit",ID_Quit), /* Hotkey rcommand-Q */ /* Ikkunan sisältö. Pitää alkaa ryhmäoliolla. */ VertGroupA, SpaceB, /* Iso väli */ /* Keskitetty nappula, johon kuuluu aputeksti */ CenteredButtonHelp("Kysymys",ID_Ask, "Vastaa hassuun kysymykseen"), SpaceB,HorizSeparator,SpaceB, /* Välit ja vaakaviiva */ /* Vaakasuuntainen ryhmä, jossa on ensin teksti vasemmalla ja sitten cycle-gadget oikealla. Cycle-gadget on tehty makron sijaan suoraan tageja käyttämällä. */ HorizGroupEAC,SpaceB, TextN("Säätila"),SpaceB,TROB_Cycle,(ULONG)CycleEntries, TRAT_ID,ID_Cycle,TRAT_Value,0, SpaceB,EndGroup, SpaceB, EndGroup, EndProject }; /* Tämä määrittely kuvaa About-valitsimen. BeginRequester() määrittelee valitsimen otsikon ja sijainnin, tässä se tulee ruudun otsikkorivin alle. Valitsin koostuu viidestä rivistä tekstiä sekä yhdestä eroke- viivasta eli "horisontaalisesta separaattorista". Lopuksi määritellään valitsimen nappulat, joita on tässä vain yksi, jonka ainoa tarkoitus on sulkea valitsin. Mitään tietoa tämä valitsin ei käyttäjältä ohjelmalle välitä. Nappula on keskitetty, ja siihen voi vastata myös Returnilla (R) ja Escapella (E). Myös "O" käy. Nappulan nimessä oleva alaviiva tekee sitä seuraavasta kirjaimesta nappulan hotkeyn. */ ProjectDefinition(abouttags) { BeginRequester("About...",TRWP_BELOWTITLEBAR), VertGroupA, Space, CenteredText3("TritonCode 1.00"), SpaceS, CenteredText("©1996 by Sami Klemola"), Space, HorizSeparator, Space, CenteredText("This program is using the"), SpaceS, CenteredText("Triton GUI creation system"), SpaceS, CenteredText("which is © by Stefan Zeiger"), Space, EndGroup, BeginRequesterGads, CenteredButtonRE("_Ok",1), EndRequester }; /* Toinen valitsin pomppaa ruudulle, tällä kertaa keskelle sitä, kun painetaan Kysymys-nappulaa. Tähän valitsimeen voi vastata kahdella tavalla, joten meillä on kaksi nappulaa. Se vaatii hieman enemmän työtä kuin yhden nappulan laittaminen. Niihinkin voi vastata hotkeyllä. Tämän valitsimen näytettyään funktio palauttaa sen nappulan tunnisteen, joka valittiin. Valitsimen tunnisteet eivät ole samaa sarjaa ikkunassa olevien kanssa, joten tässä ne ovat yksi ja nolla. */ ProjectDefinition(asktags) { BeginRequester("Kysymys",TRWP_CENTERSCREEN), VertGroupA, Space, CenteredText("Jotkut ihmiset ovat sitä mieltä, että"), SpaceS, CenteredText("heidän päänsä ympärillä on jotakin."), SpaceS, CenteredText("Tuntuuko sinusta, että vanne puristaa päätäsi?"), Space, EndGroup, BeginRequesterGads, LineArray,BeginLine, Space, CenteredButtonR("_Kyllä",1), Space, CenteredButtonE("_Ei kai",0), Space, EndLine,EndArray, EndRequester }; /* Pääohjelma avaa Tritonin ja Triton-projektin sekä asettaa pika-avun päälle heti. TR_OpenTriton()-funktiolle annetaan tiedot ohjelmasta. Niitä voi katsella Tritonin Prefs-editorilla. */ int _main(void) { LONG i; GetProgramName(cmd,32); if(!(ra=ReadArgs((STRPTR)template,args,NULL))) { PrintFault(i=IoErr(),cmd); exit(i); } if(!(TR_OpenTriton(TRITON11VERSION, TRCA_Name,s_prg,TRCA_LongName,s_prg, /* Ohjelman nimi */ TRCA_Info,(ULONG)"GUI Demo", /* Ohjelman kuvaus */ TRCA_Version,(ULONG)"1.00", /* Versionumero */ TRCA_Release,(ULONG)"1", /* Julkaisu */ TRCA_Date,(ULONG)"1-Mar-96",TAG_END))) /* Päiväys */ error("triton.library needed"); if(!(project=TR_OpenProject((struct TR_App *)Application,prod))) error(err_gui); TR_SetAttribute(project,0,TRWI_QuickHelp,TRUE); DoStuff(); cleanup(); return(RETURN_OK); }; /* DoStuff() on pääsilmukka, joka perustuu Tritonin lähettämien viestien vastaanottamiseen ja tulkintaan sekä niiden pohjalta toimimiseen. */ void DoStuff(void) { while(TRUE) { while(trmsg=(struct TR_Message *)TR_GetMsg(Application)) { /* Saapuneet viestit käsitellään luokkakohtaisesti. */ switch(trmsg->trm_Class) { /* Ikkunan sulkunappulaa on painettu. Vastataan kaikkiin viesteihin ja poistutaan. Triton tosin vapauttaa itsekin viesteille varatun muistin, mutta ei välttämättä viesteihin liittyviä resursseja, joten tällainen ReplyMsg()-silmukka on hyvä olla. */ case TRMS_CLOSEWINDOW: TR_ReplyMsg(trmsg); while(trmsg=(struct TR_Message *) TR_GetMsg(Application)) TR_ReplyMsg(trmsg); return(); /* Tritonissa on sattunut virhe. Lienee harvinaista. Periaatteessa ilmoitus pitäisi näyttää valitsimessa, mutta tulostaminen stdoutiinkin käynee, koska tätä ei pitäisi tapahtuakaan. */ case TRMS_ERROR: printf("%s: %s\n",cmd, TR_GetErrorString(trmsg->trm_Data)); break; /* NEWVALUE-viestit kertovat olion tilan muuttumisesta. Tällaisen viestin lähettävät esimerkiksi TOGGLE-tyyppiset (CHECKMARK) valikkovalinnat, kuten tässä ohjelmassa Autohelp, sekä Listview- ja Cycle-gadgetit. Olion uusi arvo on viestin datakentässä. */ case TRMS_NEWVALUE: switch(trmsg->trm_ID) { case ID_Help: TR_SetAttribute(project,0,TRWI_QuickHelp, trmsg->trm_Data); break; /* Tässä kohtaa pitäisi tietysti olla "case ID_Cycle:", jossa käsiteltäisiin säätilan vaihtuminen. Toinen mahdollisuus on toki se, että jos kyseessä on sellainen valinta, että sitä tarvitaan vasta tietyssä vaiheessa, ei tällaista tarvita, vaan tietoa tarvittaessa käytetään TR_GetAttribute()- funktiota olion tilan selvittämiseen. Tähän esimerkkiin en kumpaakaan ole laittanut tilaa viemään ja sekoittamaan ihmisiä. */ } break; /* ACTION-viestin synnyttää esimerkiksi tavallinen nappula, tässä ohjelmassa Kysymys-gadget, sekä tavallinen menuvalinta, jolla käynnistetään jokin toiminto. Alla käsitellään kaikki tämän ohjelman kolme ACTION-tyyppisiä viestejä heittelevää oliota. Olioiden kuvaavat tunnistenumerot ovat avuksi toimintojen selvittämiseksi koodista. About-menuvalinnasta aukeaa tavalliseen tapaan pieni valitsin, joka näyttää ohjelmasta tietoja. Valitsin on suoraan kopioitu Tritonin demokoodista, mutta tekstejä on tietysti hieman vaihdettu. Quit-valinta aikaansaa saman kuin ikkunan sulkunappulan painaminen, eli vastataan kaikkiin viesteihin ja poistutaan. Oikeassa ohjelmassa tässä pitäisi olla vielä valitsin, joka kysyisi, haluaako käyttäjä varmasti poistua ja antaisi hänelle vielä Cancel-option. Ask-nappulan toteutus on samantapainen kuin About-valikkovalinnan. Se näyttää valitsimen, ja oikea koodi tietysti katsoisi funktion palauttaman arvon, koska se sisältää tiedon siitä, mitä nappulaa käyttäjä painoi valitsimen sulkemiseksi. */ case TRMS_ACTION: switch(trmsg->trm_ID) { case ID_About: TR_AutoRequest(Application,project,abouttags); break; case ID_Quit: TR_ReplyMsg(trmsg); while(trmsg=(struct TR_Message *) TR_GetMsg(Application)) TR_ReplyMsg(trmsg); return(); case ID_Ask: TR_AutoRequest(Application,project,asktags); break; } break; } /* Kun viesti on käsitelty, tai ohitettu, jos se ei ollut haluttua tyyppiä, vaan esimerkiksi TRMS_KEYPRESSED, joka kertoo näppäimen painamisesta ja joita tässä ohjelmassa ei käsitellä, siihen vastataan, ja sen jälkeen jäädään odottamaan uutta viestiä. */ TR_ReplyMsg(trmsg); } TR_Wait(Application,0); } }; /* Tämä funktio tulostaa virheilmoituksen tavanomaiseen AmigaDOS-tapaan, eli formaatti on "ohjelma: virhe". Funktio käyttää _main()-funktion alussa DOSilta kysymäänsä nimeä. */ void error(u_char *str) { printf("%s: %s\n",cmd,str); cleanup(); exit(RETURN_FAIL); }; /* Tätä funktiota kutsutaan aina ohjelmasta poistuttaessa. Tässä ohjelmassa ei ole paljon siivottavaa, joten funktio sulkee vain Triton-projektin ja sitten Tritonin itsensä. Lopuksi vapautetaan argumentit, joita tässä ohjelmassa ei tosin käytetäkään. */ void cleanup(void) { if(project) TR_CloseProject(project); TR_CloseTriton(); if(ra) FreeArgs(ra); }; {3Mitä seuraavaksi? Jatkoa seuraa ensi numerossa. En ole vielä päättänyt, mikä seuraavan osan aihe on, mutta se selviää todennäköisesti viimeistään silloin, kun se on valmis. Todennäköisesti on aika alkaa käsitellä DOS-kirjastoa, koska se tarjoaa paljon kaikkien ohjelmien tarvitsemia palveluita. Samalla tai ehkä jatkossa pitää myös paneutua enemmän aikaisemmissa osissa liian nopeasti käsiteltyihin asioihin. Lähdekoodia on luvassa myös jatkossa. Palautettakin otetaan vastaan.